package cn.iocoder.springboot.lab17.dynamicdatasource.util;


import cn.iocoder.springboot.lab17.dynamicdatasource.config.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description Minio工具类
 * @Author 孙率众
 * @Date 2024/04/17
 */

@Component
@Slf4j
public class MinioUtils {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfig configuration;

    public byte[] input2byte(InputStream inStream) throws IOException {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[1024];
        boolean var3 = false;

        int rc;
        while ((rc = inStream.read(buff, 0, 1024)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        byte[] in2b = swapStream.toByteArray();
        return in2b;
    }

    /**
     * @param name 名字
     * @return boolean
     * @Description description: 判断bucket是否存在，不存在则创建
     * @Author 孙率众
     * @Date 2024/04/17
     */
    public boolean existBucket(String name) {
        boolean exists;
        try {
            exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
            if (!exists) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
                exists = true;
            }
        } catch (Exception e) {
            log.error("系统异常", e);
            exists = false;
        }
        return exists;
    }

    /**
     * @param bucketName 存储bucket名称
     * @return {@link Boolean }
     * @Description 创建存储bucket
     * @Author 孙率众
     * @Date 2024/04/17
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            log.error("系统异常", e);
        }
        return true;
    }

    /**
     * @param bucketName 存储bucket名称
     * @return {@link Boolean }
     * @Description 删除存储bucket
     * @Author 孙率众
     * @Date 2024/04/17
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            log.error("系统异常", e);
            return false;
        }
        return true;
    }

    /**
     * @param bucketName 存储bucket名称
     * @param fileName   文件名称
     * @param time       时间
     * @return {@link Map }
     * @Description 获取上传临时签名
     * @Author 孙率众
     * @Date 2024/04/17
     */
    @SneakyThrows
    public Map getPolicy(String bucketName, String fileName, ZonedDateTime time) {
        bucketName = StringUtils.isEmpty(bucketName) ? configuration.getBucketName() : bucketName;
        PostPolicy postPolicy = new PostPolicy(bucketName, time);
        postPolicy.addEqualsCondition("key", fileName);
        try {
            Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
            HashMap<String, String> map1 = new HashMap<>();
            map.forEach((k, v) -> {
                map1.put(k.replaceAll("-", ""), v);
            });
            map1.put("host", configuration.getUrl() + "/" + bucketName);
            return map1;
        } catch (Exception e) {
            log.error("系统异常", e);
        }
        return null;
    }

    /**
     * @param bucketName 存储bucket名称
     * @param objectName 对象名称
     * @param method     方法
     * @param time       时间
     * @param timeUnit   时间单位
     * @return {@link String }
     * @Description 获取上传文件的url
     * @Author 孙率众
     * @Date 2024/04/17
     */
    public String getPolicyUrl(String bucketName, String objectName, Method method, int time, TimeUnit timeUnit) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(method)
                    .bucket(StringUtils.isEmpty(bucketName) ? configuration.getBucketName() : bucketName)
                    .object(objectName)
                    .expiry(time, timeUnit).build());
        } catch (Exception e) {
            log.error("系统异常", e);
        }
        return null;
    }

    /**
     * @param bucketName 存储bucket名称
     * @param file       文件
     * @param fileName   文件名称
     * @Description 上传文件
     * @Author 孙率众
     * @Date 2024/04/17
     */
    public void upload(String bucketName, MultipartFile file, String fileName) {
        // 使用putObject上传一个文件到存储桶中。
        try {
            InputStream inputStream = file.getInputStream();
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(StringUtils.isEmpty(bucketName) ? configuration.getBucketName() : bucketName)
                    .object(fileName)
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
        } catch (Exception e) {
            log.error("系统异常", e);
        }
    }

    /**
     * @param bucketName 存储bucket名称
     * @param objectName 对象名称
     * @param time       时间
     * @param timeUnit   时间单位
     * @return {@link String }
     * @Description 根据filename获取文件访问地址
     * @Author 孙率众
     * @Date 2024/04/17
     */
    public String getUrl(String bucketName, String objectName, int time, TimeUnit timeUnit) {
        String url = null;
        try {
            url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(StringUtils.isEmpty(bucketName) ? configuration.getBucketName() : bucketName)
                    .object(objectName)
                    .expiry(time, timeUnit).build());
        } catch (Exception e) {
            log.error("系统异常", e);
        }
        return url;
    }

    /**
     * @param bucketName 存储bucket名称
     * @param fileName
     * @return {@link ResponseEntity }<{@link byte[] }>
     * @Description description: 下载文件
     * @Author 孙率众
     * @Date 2024/04/17
     */
    public ResponseEntity<byte[]> download(String bucketName, String fileName) {
        ResponseEntity<byte[]> responseEntity = null;
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = minioClient.getObject(GetObjectArgs.builder().bucket(StringUtils.isEmpty(bucketName) ? configuration.getBucketName() : bucketName).object(fileName).build());
            out = new ByteArrayOutputStream();
            IOUtils.copy(in, out);
            //封装返回值
            byte[] bytes = out.toByteArray();
            HttpHeaders headers = new HttpHeaders();
            try {
                headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                log.error("系统异常", e);
            }
            headers.setContentLength(bytes.length);
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setAccessControlExposeHeaders(Arrays.asList("*"));
            responseEntity = new ResponseEntity<>(bytes, headers, HttpStatus.OK);
        } catch (Exception e) {
            log.error("系统异常", e);
        } finally {
            try {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        log.error("系统异常", e);
                    }
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                log.error("系统异常", e);
            }
        }
        return responseEntity;
    }

    /**
     * @param bucketName 存储bucket名称
     * @param objectFile 对象文件
     * @return {@link String }
     * @Description 根据文件名和桶获取文件路径
     * @Author 孙率众
     * @Date 2024/04/17
     */
    public String getFileUrl(String bucketName, String objectFile) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(StringUtils.isEmpty(bucketName) ? configuration.getBucketName() : bucketName)
                    .object(objectFile)
                    .build()
            );
        } catch (Exception e) {
            log.error("系统异常", e);
        }
        return null;
    }

    public void createFile(String fileName, byte[] bytes, String bucketName) {
        try {
            bucketName = StringUtils.isEmpty(bucketName) ? configuration.getBucketName() : bucketName;
            BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
            boolean flag = minioClient.bucketExists(bucketExistsArgs);
            if (!flag) {
                MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(bucketName).build();
                minioClient.makeBucket(makeBucketArgs);
            }
            //fileName：存储桶里的对象名称
            PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(bucketName).object(fileName)
                    .stream(new ByteArrayInputStream(bytes), bytes.length, -1).build();
            // 上传到minio
            minioClient.putObject(putObjectArgs);
        } catch (Exception e) {
            log.error("系统异常", e);
        }
    }
}

